/*
 * Copyright (C) 2010-2011 Comcast Cable.  All Rights Reserved.
 */
package com.hercules.android.receiver.painting.resources;

import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.MotionEvent;
import android.widget.EditText;

import com.hercules.android.receiver.LogUtil;
import com.hercules.android.receiver.handlers.events.EventRaisingException;
import com.hercules.android.receiver.model.commands.XRECallCommand;
import com.hercules.android.receiver.model.commands.XRECommand;
import com.hercules.android.receiver.model.commands.XRESetCommand;
import com.hercules.android.receiver.model.events.XRETextInputEvent;
import com.hercules.android.receiver.model.objects.XRETextInput;
import com.hercules.android.receiver.painting.PaintersUtil;
import com.hercules.android.receiver.painting.XREEditText;
import com.hercules.android.receiver.painting.views.XRELayoutParams;

/**
 * Painter for {@link XRETextInput} resource. It will use {@link EditText} to display text and edit text.
 * <p>
 * AndroidAssembly1 this class was added in Android Assembly 1
 * <p>
 * <b>Thread safety:</b> Not thread safe, because base class is not thread safe
 *
 * @author 7realm
 * @version 1.0
 */
public class XRETextInputPainter extends BaseXREResourcePainter implements TextWatcher {
    /**
     * Represents the {@link EditText} that will be used as text input.
     * <p>
     * It is initialized in init method, updated in handleCommand method and destroyed in finish method.
     */
    private XREEditText editText;

    /**
     * Constructor for class {@link XRETextInputPainter}.
     *
     * @param xreResource the {@link XRETextInput}
     */
    public XRETextInputPainter(XRETextInput xreResource) {
        super(xreResource);
    }

    /**
     * Performs initialize actions.
     *
     * @throws IllegalStateException if required fields are not set
     */
    @Override
    public void init() {
        final String methodName = "init";
        LogUtil.enter(getLogger(), this, methodName);

        try {
            PaintersUtil.checkState(getReceiver(), "receiver");
            PaintersUtil.checkState(getXREView(), "xreView");
            PaintersUtil.checkState(getAndroidView(), "androidView");
            PaintersUtil.checkState(getEventRaiser(), "eventRaiser");

            // create edit text
            editText = new XREEditText(getAndroidView().getContext()) {
                /**
                 * Touch handler for EditText, introduce to disable focusing on click.
                 *
                 * @param event the MotionEvent.
                 * @return always false
                 */
                @Override
                public boolean onTouchEvent(MotionEvent event) {
                    return false;
                }
            };
            editText.addTextChangedListener(this);
            editText.setSelectAllOnFocus(true);

            // add EditText to UI view
            // create and add to parent
        //	AndroidXREView parentView = (AndroidXREView) getAndroidView().getParent();
        //	parentView.removeView(getAndroidView());

        //	AndroidXREView rootView = (AndroidXREView) getReceiver().getRootView();
        //	rootView.addView(getAndroidView());
        	getAndroidView().addView(editText, 0);

            // set properties and invalidate
            setProperties(getTextInput(), editText);
            
            editText.setLayoutParams(new XRELayoutParams(getXREView()));
        	//editText.setWidth(getXREView().getWidth());
        	//editText.setHeight(getXREView().getHeight());
        	editText.setPadding(3, 3, 3, 3);
        	
            getAndroidView().invalidate();
        } catch (IllegalStateException e) {
            throw LogUtil.error(getLogger(), this, methodName, e);
        }

        LogUtil.exit(getLogger(), this, methodName);
    }

    /**
     * Performs clean up.
     *
     * @throws IllegalStateException if required fields are not set
     */
    @Override
    public void finish() {
        String methodName = "finish";
        LogUtil.enter(getLogger(), this, methodName);

        try {
            PaintersUtil.checkState(getReceiver(), "receiver");
            PaintersUtil.checkState(editText, "editText");

            // remove from view
            getAndroidView().removeView(editText);
        } catch (IllegalStateException e) {
            throw LogUtil.error(getLogger(), this, methodName, e);
        }

        LogUtil.exit(getLogger(), this, methodName);
    }

    /**
     * Handle {@link XRECommand}.
     *
     * @param command the command to handle
     * @throws IllegalStateException if required fields are not set
     */
    @Override
    public void handleCommand(XRECommand command) {
        String methodName = "handleCommand";
        LogUtil.enter(getLogger(), this, methodName);

        try {
            PaintersUtil.checkState(editText, "editText");

            // handle property change
            if (command instanceof XRESetCommand) {
                setProperties(getTextInput(), editText);
                
                editText.setLayoutParams(new XRELayoutParams(getXREView()));
            	editText.setPadding(3, 3, 3, 3);
            }

            // handle activate command
            if (command instanceof XRECallCommand) {
                final XRECallCommand callCommand = (XRECallCommand) command;

                if ("activate".equals(callCommand.getMethod())) {
                    // request focus for activate
                    editText.requestFocus();
                    
                    getReceiver().getLocalBehaviorData().setFocusedView(editText);
                    getReceiver().getLocalBehaviorData().setFocusedReceiver(getReceiver());
                    getReceiver().getLocalBehaviorData().setFocusedXREView(getAndroidView().getXREView());
                }
            }
        } catch (IllegalStateException e) {
            throw LogUtil.error(getLogger(), this, methodName, e);
        }
        LogUtil.exit(getLogger(), this, methodName);
    }

    /**
     * Gets {@link XRETextInput}.
     *
     * @return the corresponding {@link XRETextInput}
     */
    private XRETextInput getTextInput() {
        return (XRETextInput) getXREResource();
    }

    /**
     * Sets properties of {@link EditText} using values in {@link XRETextInput}.
     *
     * @param textInput the {@link XRETextInput}
     * @param editText the {@link EditText}
     */
    private static void setProperties(final XRETextInput textInput, final EditText editText) {
        // set text and other properties
        editText.setText(textInput.getText());
        editText.setTextColor(textInput.getColor());
        editText.setTextSize(textInput.getSize());
        editText.setSingleLine();

        // set typeface
        if (textInput.getFont() != null) {
            editText.setTypeface(PaintersUtil.createTypeface(textInput.getFont()));
        }

        // set masked input
        if (textInput.isMaskText()) {
            editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
        } else {
            editText.setInputType(InputType.TYPE_CLASS_TEXT);
        }
    }

    /**
     * Notify after text is changed.
     *
     * @param editable the current {@link Editable} object
     */
    public void afterTextChanged(Editable editable) {
        // empty
    }

    /**
     * Notify when text is about to change.
     *
     * @param charsequence the char sequence
     * @param i start
     * @param j count
     * @param k after
     */
    public void beforeTextChanged(CharSequence charsequence, int i, int j, int k) {
        // empty
    }

    /**
     * Notify when text is changed.
     *
     * @param charsequence the char sequence
     * @param i start
     * @param j count
     * @param k after
     */
    public void onTextChanged(CharSequence charsequence, int i, int j, int k) {
        synchronized (this) {
            XRETextInput textInput = getTextInput();
            String currentText = editText.getText().toString();
            if (!textInput.getText().equals(currentText)) {
                textInput.setText(currentText);

                // create event
                XRETextInputEvent xreEvent = new XRETextInputEvent();
                xreEvent.setName(XRETextInputEvent.ON_CHANGED_EVENT_NAME);
                xreEvent.setSource(textInput.getId());
                xreEvent.setText(textInput.getText());

                try {
                    // raise event
                    getEventRaiser().raiseEvent(xreEvent, getReceiver(), true);
                } catch (EventRaisingException e) {
                    LogUtil.error(getLogger(), this, "onKey", e);
                }
            }
        }
    }
}
